﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Xml;

namespace Tum.CollabXT.VModellXT.Tailoring
{
    public class ProjectCharacteristic
    {
        private List<ProjectCharacteristicValue> _Values;

        private ProjectCharacteristic() { _Values = new List<ProjectCharacteristicValue>(); }

        public static ProjectCharacteristic Create(string nodeId, XmlDocument modelDoc)
        {
            XmlNode pcNode = modelDoc.SelectSingleNode("//Projektmerkmal[@id='" + nodeId + "']");
            return (Create(pcNode, modelDoc));
        }

        public static ProjectCharacteristic Create(XmlNode pcNode, XmlDocument modelDoc)
        {            
            ProjectCharacteristic pc = new ProjectCharacteristic();
            pc.Id = pcNode.Attributes["id"].Value;
            pc.Name = pcNode.SelectSingleNode("Name").InnerText;

            string defaultValueId = pcNode.SelectSingleNode("StandardwertRef/@link").Value;

            XmlNodeList valueNodes = pcNode.SelectNodes("Wert");
            foreach (XmlNode valNode in valueNodes)
            {
                string valNodeId = valNode.Attributes["id"].Value;
                var newCharacteristicVal = new ProjectCharacteristicValue(valNode, modelDoc);
                pc.Values.Add(newCharacteristicVal);
                if (valNodeId.Equals(defaultValueId, StringComparison.InvariantCultureIgnoreCase))
                    pc.DefaultValue = newCharacteristicVal;
            }

            return (pc);
        }

        #region Metadata
        /// <summary>
        /// Id of the characteristic
        /// </summary>
        public string Id
        {
            get;
            set;
        }

        /// <summary>
        /// Name of the characteristic
        /// </summary>
        public string Name
        {
            get;
            set;
        }
 
        /// <summary>
        /// Default value of the characteristic
        /// </summary>
        public ProjectCharacteristicValue DefaultValue
        {
            get;
            set;
        }
        #endregion

        /// <summary>
        /// Possible Values of this characteristic
        /// </summary>
        public List<ProjectCharacteristicValue> Values
        {
            get { return _Values; }
            set { _Values = value; }
        }

        public override string ToString()
        {
            return Name;
        }
    }

    public class ProjectCharacteristicValue
    {
        List<ProcessModule> _ProcessModules;
        List<ProcessExecutionModuleSpecification> _ProcessExecutionModuleSpecs;
        List<ProcessExecutionModule> _ProjectExecutionModules;

        private ProjectCharacteristicValue() { }

        public ProjectCharacteristicValue(XmlNode pcvNode, XmlDocument modelDoc)
        {
            _ProcessModules = new List<ProcessModule>();
            _ProjectExecutionModules = new List<ProcessExecutionModule>();
            _ProcessExecutionModuleSpecs = new List<ProcessExecutionModuleSpecification>();

            Id = pcvNode.Attributes["id"].Value;
            Name = pcvNode.SelectSingleNode("Name").InnerText;

            #region initialize process modules
            XmlNodeList pmList = pcvNode.SelectNodes("BedingteVorgehensbausteine/BedingterVorgehensbaustein/VorgehensbausteinRef");
            foreach (XmlNode pmNode in pmList)
            {
                _ProcessModules.Add(ProcessModule.Create(pmNode.Attributes["link"].Value, modelDoc));
            }

            #endregion

            #region initialize process execution module specs
            XmlNodeList pemsList = pcvNode.SelectNodes("BedingteAblaufbausteinspezifikationen/BedingteAblaufbausteinspezifikation/AblaufbausteinspezifikationRef");
            foreach (XmlNode pemsNode in pemsList)
            {
                _ProcessExecutionModuleSpecs.Add(ProcessExecutionModuleSpecification.Create(pemsNode.Attributes["link"].Value, modelDoc));
            }
            #endregion

            #region initialize process execution modules
            XmlNodeList pemList = pcvNode.SelectNodes("BedingteAblaufbausteine/BedingterAblaufbaustein/AblaufbausteinRef");
            foreach (XmlNode pemNode in pemList)
            {
                _ProjectExecutionModules.Add(ProcessExecutionModule.Create(pemNode.Attributes["link"].Value, modelDoc));
            }
            #endregion
        }

        #region Metadata
        /// <summary>
        /// Id of the value
        /// </summary>
        public String Id
        {
            get;
            set;
        }

        /// <summary>
        /// Name of the value
        /// </summary>
        public string Name
        {
            get;
            set;
        }
        #endregion

        /// <summary>
        /// Process modules referred by the value
        /// </summary>
        public List<ProcessModule> ProcessModules
        {
            get { return _ProcessModules; }
            set { _ProcessModules = value; }
        }

        /// <summary>
        /// Process execution module specifications referred by this value
        /// </summary>
        public List<ProcessExecutionModuleSpecification> ProcessExecutionModuleSpecs
        {
            get { return _ProcessExecutionModuleSpecs; }
            set { _ProcessExecutionModuleSpecs = value; }
        }

        /// <summary>
        /// Process execution modules referred by this value
        /// </summary>
        public List<ProcessExecutionModule> ProcessExecutionModules
        {
            get { return _ProjectExecutionModules; }
            set { _ProjectExecutionModules = value; }
        }

        public override string ToString()
        {
            return Name;
        }
    }

    public class ProjectType
    {
        List<ProjectTypeVariant> _ProjectTypeVariants;
        List<ProcessModule> _ProcessModules;
        List<ProcessExecutionModuleSpecification> _ProcessExecutionModuleSpecs;
        List<ProjectCharacteristic> _ProjectCharacteristics;

        private ProjectType() { }

        internal ProjectType(XmlNode ptNode)//, XmlDocument modelDoc)
        {
            _ProcessModules = new List<ProcessModule>();
            _ProjectTypeVariants = new List<ProjectTypeVariant>();
            _ProcessExecutionModuleSpecs = new List<ProcessExecutionModuleSpecification>();
            _ProjectCharacteristics = new List<ProjectCharacteristic>();

            Id = ptNode.Attributes["id"].Value;
            Name = ptNode.SelectSingleNode("Name").InnerText;

            #region initialize process modules
            XmlNodeList pmList = ptNode.SelectNodes("BedingteVorgehensbausteine/BedingterVorgehensbaustein/VorgehensbausteinRef");
            foreach (XmlNode pmNode in pmList)
            {
                _ProcessModules.Add(ProcessModule.Create(pmNode.Attributes["link"].Value, ptNode.OwnerDocument));
            }

            #endregion

            #region initialize project type variants
            XmlNodeList ptvList = ptNode.OwnerDocument.SelectNodes("//Projekttypvariante/ProjekttypRef[@link ='" + Id + "']/..");
            foreach (XmlNode ptvNode in ptvList)
            {
                _ProjectTypeVariants.Add(new ProjectTypeVariant(ptvNode));
            }
            #endregion

            #region initialize process execution module specs
            XmlNodeList pemList = ptNode.SelectNodes("BedingteAblaufbausteinspezifikationen/BedingteAblaufbausteinspezifikation/AblaufbausteinspezifikationRef");
            foreach (XmlNode pemNode in pemList)
            {
                _ProcessExecutionModuleSpecs.Add(ProcessExecutionModuleSpecification.Create(pemNode.Attributes["link"].Value, ptNode.OwnerDocument));
            }

            #endregion

            #region initialize PES-specification Id
            PDSSpecification = ptNode.SelectSingleNode("PDS-Spezifikation/AblaufbausteinspezifikationRef").Attributes["link"].Value;
            #endregion

            #region initialize project charateristics
            XmlNodeList pcList = ptNode.SelectNodes("BedingteProjektmerkmale/BedingtesProjektmerkmal/ProjektmerkmalRef");
            foreach (XmlNode pcNode in pcList)
            {
                _ProjectCharacteristics.Add(ProjectCharacteristic.Create(pcNode.Attributes["link"].Value, ptNode.OwnerDocument));
            }
            #endregion
        }

        #region Identification
        /// <summary>
        /// Id of the project type
        /// </summary>
        public string Id
        {
            get;
            set;
        }

        /// <summary>
        /// Name of the project type
        /// </summary>
        public string Name
        {
            get;
            set;
        }
        #endregion

        public List<ProjectTypeVariant> ProjectTypeVariants
        {
            get { return _ProjectTypeVariants; }
            set { _ProjectTypeVariants = value; }
        }

        public List<ProcessModule> ProcessModules
        {
            get { return _ProcessModules; }
            set { _ProcessModules = value; }
        }

        /// <summary>
        /// Process execution module specifications referred by this project type
        /// </summary>
        public List<ProcessExecutionModuleSpecification> ProcessExecutionModuleSpecs
        {
            get { return _ProcessExecutionModuleSpecs; }
            set { _ProcessExecutionModuleSpecs = value; }
        }

        /// <summary>
        /// Project characteristics referred by the project type
        /// </summary>
        public List<ProjectCharacteristic> ProjectCharacteristics
        {
            get { return _ProjectCharacteristics; }
            set { _ProjectCharacteristics = value; }
        }

        /// <summary>
        /// Id of the PDS-Spec assigend to the project type
        /// </summary>
        public string PDSSpecification
        {
            get;
            set;
        }

        public override string ToString()
        {
            return Name;
        }
    }

    public class ProjectTypeVariant
    {
        List<ProcessModule> _ProcessModules;
        List<ProcessExecutionModuleSpecification> _ProcessExecutionModuleSpecs;
        List<ProjectCharacteristic> _ProjectCharacteristics;
        List<ProcessExecutionModule> _ProjectExecutionModules;

        private ProjectTypeVariant() { }

        internal ProjectTypeVariant(XmlNode ptvNode)
        {
            _ProcessModules = new List<ProcessModule>();
            _ProjectExecutionModules = new List<ProcessExecutionModule>();
            _ProcessExecutionModuleSpecs = new List<ProcessExecutionModuleSpecification>();
            _ProjectCharacteristics = new List<ProjectCharacteristic>();

            Id = ptvNode.Attributes["id"].Value;
            Name = ptvNode.SelectSingleNode("Name").InnerText;

            #region initialize process modules
            XmlNodeList pmList = ptvNode.SelectNodes("BedingteVorgehensbausteine/BedingterVorgehensbaustein/VorgehensbausteinRef");
            foreach (XmlNode pmNode in pmList)
            {
                _ProcessModules.Add(ProcessModule.Create(pmNode.Attributes["link"].Value, ptvNode.OwnerDocument));
            }

            #endregion

            #region initialize process execution module specs
            XmlNodeList pemsList = ptvNode.SelectNodes("BedingteAblaufbausteinspezifikationen/BedingteAblaufbausteinspezifikation/AblaufbausteinspezifikationRef");
            foreach (XmlNode pemsNode in pemsList)
            {
                _ProcessExecutionModuleSpecs.Add(ProcessExecutionModuleSpecification.Create(pemsNode.Attributes["link"].Value, ptvNode.OwnerDocument));
            }
            #endregion

            #region initialize process execution modules
            XmlNodeList pemList = ptvNode.SelectNodes("BedingteAblaufbausteine/BedingterAblaufbaustein/AblaufbausteinRef");
            foreach (XmlNode pemNode in pemList)
            {
                _ProjectExecutionModules.Add(ProcessExecutionModule.Create(pemNode.Attributes["link"].Value, ptvNode.OwnerDocument));
            }
            #endregion

            #region initialize project charateristics
            XmlNodeList pcList = ptvNode.SelectNodes("BedingteProjektmerkmale/BedingtesProjektmerkmal/ProjektmerkmalRef");
            foreach (XmlNode pcNode in pcList)
            {
                _ProjectCharacteristics.Add(ProjectCharacteristic.Create(pcNode.Attributes["link"].Value, ptvNode.OwnerDocument));
            }
            #endregion
        }

        /// <summary>
        /// Id of the project type variant
        /// </summary>
        public string Id
        {
            get;
            set;
        }

        /// <summary>
        /// Name of the project type variant
        /// </summary>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Process modules referred by the project type variant
        /// </summary>
        public List<ProcessModule> ProcessModules
        {
            get { return _ProcessModules; }
            set { _ProcessModules = value; }
        }

        /// <summary>
        /// Process execution module specifications referred by this project type
        /// </summary>
        public List<ProcessExecutionModuleSpecification> ProcessExecutionModuleSpecs
        {
            get { return _ProcessExecutionModuleSpecs; }
            set { _ProcessExecutionModuleSpecs = value; }
        }

        /// <summary>
        /// Process execution modules referred by this project type
        /// </summary>
        public List<ProcessExecutionModule> ProcessExecutionModules
        {
            get { return _ProjectExecutionModules; }
            set { _ProjectExecutionModules = value; }
        }

        /// <summary>
        /// Project characteristics referred by the project type
        /// </summary>
        public List<ProjectCharacteristic> ProjectCharacteristics
        {
            get { return _ProjectCharacteristics; }
            set { _ProjectCharacteristics = value; }
        }

        public override string ToString()
        {
            return Name;
        }
    }
}
